/*******************************************************************************
 * Copyright (c) 2013 Davide Cabbia.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     Davide Cabbia - initial API and implementation
 ******************************************************************************/
package ditta;


import interfaccia.*;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.MalformedURLException;
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.util.Iterator;
import java.util.Vector;


public class Ditta {
	private static final String host = "localhost/Ditta";
	protected DittaImpl server;
	public Vector <IBase> listaBasi;
	Vector <String> listaNomiBasi;
	Vector <IAutotreno> listaViaggiatori;
	private DittaGui gui;
	TGestioneBasi gestioneBasi;
	public Ditta(){
		try {
			//creo istanza oggetto remoto
			server = new DittaImpl();
			//genero un nome con cui pubblicizzare l'oggetto
			String rmiNome = "rmi://" + host;
			//registro oggetto con il suo nome nell'RMI registro
			Naming.rebind(rmiNome, server);

		} catch (RemoteException e) {
			System.out.println("Impossibile stabilire il collegamento al registro RMI");
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("Ditta avviata!");		
		
		listaBasi= new Vector<IBase>();
		listaNomiBasi =new Vector<String>();
		listaViaggiatori =new Vector<IAutotreno>();
		gui= new DittaGui();
		gui.getButtonInvio().addActionListener(new DittaAction());
		gui.getButtonChiusura().addActionListener(new DittaAction());
		gestioneBasi = new TGestioneBasi();

	}
	private IBase cercaRif(String str){
		if(listaNomiBasi.contains(str)){
			int size=listaNomiBasi.size();
			int it=0;
			int indexGiusto=-1;
			while(it<size)
			{
				if(listaNomiBasi.elementAt(it).equals(str)){
					indexGiusto=it;
					it=size;
				}
				it++;	
			}
			if(indexGiusto>=0){
				return listaBasi.elementAt(indexGiusto);
			}
			else{
				return null;
			}	
		}
		return null;
	}
	
	private class DittaAction implements ActionListener {
	    
		
		/*
		 * override del metodo actionPerformed dell'interfaccia ActionListener.
		 * Se non connesso, viene effettuato un tentativo di connessione all'RMI
		 * Registry, altrimenti viene eseguita la disconnessione del server.
		 */
	
		public void actionPerformed(ActionEvent e) {
			if(e.getSource()==gui.getButtonInvio()){
				//evento INVIO nuova commessa				
				
				String mittente = gui.getMittente();
				String destinatario = gui.getDestinatario();
				if(mittente==null || destinatario==null)
					return;
				int quantita;
				try {
					quantita = Integer.parseInt(gui.getQuantita());
				} catch (NumberFormatException e2) {
					// TODO Auto-generated catch block
					System.out.println("Non è stato inserito un intero nel campo quantità. Invio ingnorato.");
					return;
				}
				IBase rifMittente = null;
				IBase rifDestinatario = null;
				synchronized(listaBasi){
					try {
						
						rifMittente = cercaRif(mittente);
						rifMittente.ciSei();
					}
					catch (RemoteException e1) {
						System.out.println("La base " + mittente +" non è contattabile.");
						listaBasi.notify();
						return;
					}
					try{		
						rifDestinatario = cercaRif(destinatario);
						rifDestinatario.ciSei();
					}
					catch(RemoteException e1)
					{
						System.out.println("La base " + destinatario +" non è contattabile.");
						listaBasi.notify();
						return;
					}
				}
				try {
					rifMittente.aggiungiConsegna(rifDestinatario, quantita);
				} catch (RemoteException e1) {
					System.out.println("Basi non contattabili.");
				}
			}
			if(e.getSource()==gui.getButtonChiusura()){
				//evento CHIUSURA ditta

				try {
					gestioneBasi.interrupt();

					for(int i=0;i<listaBasi.size();++i)
						try{
							listaBasi.get(i).interrompiAttivita(); //interrompo Gestore trasporti Basi e termino gli autotreni parcheggiati		
						}
						catch(ConnectException ex)
						{
							gui.append("Base "+listaNomiBasi.elementAt(i)+" non attiva, impossibile comunicare chiusura");
							System.out.println("Base "+listaNomiBasi.elementAt(i)+" non attiva, impossibile comunicare chiusura");
						}
						
					for(int i=0;i<listaViaggiatori.size();++i){
						try{
							listaViaggiatori.get(i).interrompiAttivita();//interrompo tutti gli autotreni in viaggio
						}
						catch(RemoteException e1)
						{
							System.out.println("Viaggiatore presente non interrotto correttamente");
						}
					}
					gui.getButtonChiusura().setEnabled(false);
					gui.getButtonInvio().setEnabled(false);
								
					
				} catch (RemoteException e1) {
					e1.printStackTrace();
				}
			}
			if(e.getSource()==gui.getMittente()){
				System.out.println("mittente");
			}
		}
	}// -------- Class StartServerHandler

	
	
	private void elencoBasi(){
		int it=0;
		int size=listaBasi.size();
		System.out.println("\nBasi: ");
		while(it<size)
		{
			try {
				Vector<IAutotreno> listaAutotreni=listaBasi.elementAt(it).listaAutotreni();
				int sizea=listaAutotreni.size();
				int ita=0;
				System.out.print(listaNomiBasi.elementAt(it)+" Autotreni: " + listaBasi.elementAt(it).listaAutotreniString()
						+ " Coda: "+ listaBasi.elementAt(it).codaLavoriString());
				System.out.println("\n");
				it++;	
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	
	
	public class DittaImpl extends UnicastRemoteObject implements IDitta {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public DittaImpl() throws RemoteException {}

		public boolean registrazioneBase(IBase base,String nome)  {
			boolean registrata=false;
			try{
				synchronized(listaBasi){
					if(listaNomiBasi.contains(nome)&&listaBasi.contains(base))
						registrata = false;
					else{
						listaBasi.addElement(base);
						listaNomiBasi.addElement(nome);
						gui.aggiungiBase(nome);
						registrata = true;
						listaBasi.notifyAll();
					}
				}
				return registrata;
			}
			catch(Exception e){
				System.out.println("Impossibile aggiungere Base alla Ditta");
			}
			
			return false;
		}

		public void registrazioneAutotreno(IAutotreno autotreno,  
				String nomeBase) throws RemoteException {
			new TAssegnaBase(autotreno, nomeBase);
		}
		
		@Override
		public void trasportoCompletato(IBase mittente, IAutotreno autotreno, IBase destinatario)
				throws RemoteException {
			gui.trasportoCompletato(autotreno.nomeAutotreno(),destinatario.nomeBase());
			listaViaggiatori.remove(autotreno);
			mittente.segnalaViaLibera(destinatario);
		}

		@Override
		public void riuscitaChiusura(String nome) throws RemoteException {
			gui.append(nome + " ha chiuso le attivita' pendenti in maniera corretta");
		}

		@Override
		public void comunicaPartenza(IAutotreno autotreno)
				throws RemoteException {
			listaViaggiatori.add(autotreno);
			
		}

		@Override
		public void controllaPresenzaBasi() throws RemoteException {
			synchronized(listaBasi){
				listaBasi.notify();
			}
		}
	}
	
	
	
	class TGestioneBasi extends Thread {
		IAutotreno autotreno;
		IBase base;
		/*
		 * costruttore della classe TGestioneOrdini
		 */
		public TGestioneBasi() {
			start();
		}
		/*
		 * override del metodo run della classe Thread.
		 */
		public void run() {
			try {
				while(true){
					synchronized(listaBasi){
						for(int i=0;i<listaBasi.size();++i){
							try {
								listaBasi.elementAt(i).ciSei();									
							} catch (RemoteException e) {
								listaBasi.remove(i);
								System.out.println("Base " + listaNomiBasi.elementAt(i) + "rimossa.");
								listaNomiBasi.remove(i);
								gui.aggiornaEtichetteBasi(listaNomiBasi);
							}
						}
						listaBasi.wait();
					}
					
					if (Thread.interrupted()) {
					    throw new InterruptedException();
					}
				}
			} catch (InterruptedException e) {
				System.out.println("Ditta Terminata correttamente");
				gui.append("Ditta ha chiuso le attivita' pendenti in maniera corretta");
			}
		}
	}// -------- Class 
	
	
	class TAssegnaBase extends Thread {
		IAutotreno _autotreno;
		String _nomeBase;
		
		/*
		 * costruttore della classe TGestioneOrdini
		 */
		public TAssegnaBase(IAutotreno autotreno, String nomeBase) {
			_nomeBase = nomeBase;
			_autotreno = autotreno;
			
			start();
		}
		/*
		 * override del metodo run della classe Thread.
		 */
		public void run() {
			try {
				synchronized(listaBasi){
					while(true){
						IBase rifBase=cercaRif(_nomeBase);
						if(rifBase==null){
							listaBasi.wait();
						}
						else{
							_autotreno.impostaBase(rifBase, _autotreno);
							throw new InterruptedException();
						}
					}
				}
			} catch (InterruptedException e) {
				return;
			} catch (RemoteException e) {
				return;
			}
		}
	}// -------- Class 

}
